package com.hua.util;

import android.os.Environment;
import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;

/**
 * 类名: CommDownloadUtils
 * 作者: 蒋剑华
 * 创建时间: 2025/11/7 10:24
 * 类描述：文件下载工具类（支持单文件/多文件下载、进度监听、暂停/取消）
 * 依赖 ThreadPoolUtils 线程池（前面实现的单例线程池）
 */
public class CommDownloadUtils {

    long downloadedSize = 0; // 已下载大小（支持断点续传）
    long totalSize = 0;      // 文件总大小
    private static final String TAG = "<---HUA--->";
    private static volatile CommDownloadUtils sInstance;

    // 下载任务缓存（key：下载URL，value：下载任务），支持并发操作
    private final Map<String, DownloadTask> mDownloadTaskMap = new ConcurrentHashMap<>();
    // 应用私有下载目录（默认：/data/data/包名/files/Download）
    private String mDefaultDownloadDir;

    /**
     * 方法名：CommDownloadUtils
     * 作者：蒋剑华
     * 创建时间：2025/11/7 10:25
     * 参数描述：无参数
     * 方法描述：调用initDefaultDir 设置初始下载目录
     * 返回类型：构造器无返回类型
     */
    private CommDownloadUtils() {
        initDefaultDir();
    }

    /**
     * 方法名：getInstance
     * 作者：蒋剑华
     * 创建时间：2025/11/7 10:26
     * 参数描述：获取当前类的单例
     * 方法描述：无参数
     * 返回类型：返回是当前类，也就是this
     */
    public static CommDownloadUtils getInstance() {
        if (sInstance == null) {
            synchronized (CommDownloadUtils.class) {
                if (sInstance == null) {
                    sInstance = new CommDownloadUtils();
                }
            }
        }
        return sInstance;
    }

    /**
     * 初始化默认下载目录（无需存储权限）
     */
    /**
     * 方法名：initDefaultDir
     * 作者：蒋剑华
     * 创建时间：2025/11/7 10:27
     * 参数描述：无参数
     * 方法描述：初始化默认下载目录（无需存储权限）
     * 返回类型：无返回
     */
    private void initDefaultDir() {
        File appDir = AppUtils.getAppContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
        if (appDir == null) {
            appDir = new File(AppUtils.getAppContext().getFilesDir(), "Download");
        }
        if (!appDir.exists()) {
            appDir.mkdirs();
        }
        mDefaultDownloadDir = appDir.getAbsolutePath();
        Log.d(TAG, "默认下载目录：" + mDefaultDownloadDir);
    }

    // -------------------------- 单文件下载 --------------------------
    /**
     * 方法名：downloadSingleFile
     * 作者：蒋剑华
     * 创建时间：2025/11/7 10:27
     * 参数描述：
     *
     * @param downloadUrl 下载链接
     * @param listener    下载监听（进度、成功、失败）
     *                    方法描述：单文件下载（使用默认下载目录）
     *                    返回类型：
     */
    public void downloadSingleFile(String downloadUrl, DownloadListener listener) {
        downloadSingleFile(downloadUrl, mDefaultDownloadDir, null, listener);
    }

    /**
     * 单文件下载（自定义存储路径和文件名）
     *
     * @param downloadUrl 下载链接
     * @param saveDir     存储目录（如：/sdcard/MyDownload）
     * @param fileName    保存文件名（null 则自动从 URL 解析）
     * @param listener    下载监听
     */
    public void downloadSingleFile(String downloadUrl, String saveDir, String fileName, DownloadListener listener) {
        // 校验参数
        if (downloadUrl == null || downloadUrl.isEmpty()) {
            if (listener != null)
                listener.onFailure(downloadUrl, new IllegalArgumentException("下载URL为空"));
            return;
        }

        // 自动解析文件名（如果未指定）
        if (fileName == null || fileName.isEmpty()) {
            fileName = parseFileNameFromUrl(downloadUrl);
        }

        // 校验存储目录
        File dir = new File(saveDir);
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                if (listener != null)
                    listener.onFailure(downloadUrl, new IOException("创建存储目录失败：" + saveDir));
                return;
            }
        }

        // 检查是否已存在相同任务（避免重复下载）
        if (mDownloadTaskMap.containsKey(downloadUrl)) {
            DownloadTask existingTask = mDownloadTaskMap.get(downloadUrl);
            if (existingTask.isRunning()) {
                if (listener != null)
                    listener.onFailure(downloadUrl, new IllegalStateException("该文件正在下载中"));
                return;
            } else {
                mDownloadTaskMap.remove(downloadUrl); // 移除已完成/取消的任务
            }
        }

        // 创建下载任务
        DownloadTask task = new DownloadTask(downloadUrl, saveDir, fileName, listener);
        mDownloadTaskMap.put(downloadUrl, task);
        // 提交到线程池执行
        CommThreadPoolUtils.runOnSubThread(task);
    }

    // -------------------------- 多文件批量下载 --------------------------

    /**
     * 多文件批量下载（使用默认下载目录，所有文件下载完成后回调）
     *
     * @param downloadUrls  下载链接列表
     * @param batchListener 批量下载监听
     */
    public void downloadBatchFiles(List<String> downloadUrls, BatchDownloadListener batchListener) {
        downloadBatchFiles(downloadUrls, mDefaultDownloadDir, null, batchListener);
    }

    /**
     * 多文件批量下载（自定义存储目录）
     *
     * @param downloadUrls  下载链接列表
     * @param saveDir       存储目录
     * @param fileNames     文件名列表（与 URL 顺序对应，null 则自动解析）
     * @param batchListener 批量下载监听
     */
    public void downloadBatchFiles(List<String> downloadUrls, String saveDir, List<String> fileNames, BatchDownloadListener batchListener) {
        if (downloadUrls == null || downloadUrls.isEmpty()) {
            if (batchListener != null)
                batchListener.onBatchFailure(new IllegalArgumentException("下载链接列表为空"));
            return;
        }

        // 文件名列表校验（长度不一致则自动解析）
        if (fileNames != null && fileNames.size() != downloadUrls.size()) {
            fileNames = null;
            Log.w(TAG, "文件名列表长度与URL列表不一致，自动解析文件名");
        }

        // 计数锁：等待所有任务完成
        CountDownLatch latch = new CountDownLatch(downloadUrls.size());
        List<DownloadInfo> successList = new ArrayList<>();
        List<DownloadFailInfo> failList = new ArrayList<>();

        // 遍历创建单个下载任务
        for (int i = 0; i < downloadUrls.size(); i++) {
            String url = downloadUrls.get(i);
            String fileName = (fileNames != null) ? fileNames.get(i) : parseFileNameFromUrl(url);

            downloadSingleFile(url, saveDir, fileName, new DownloadListener() {
                @Override
                public void onStart(String url, long totalSize) {
                    if (batchListener != null) {
                        batchListener.onSingleStart(url, totalSize);
                    }
                }

                @Override
                public void onProgress(String url, long downloadedSize, long totalSize, int progress, float speed) {
                    if (batchListener != null) {
                        batchListener.onSingleProgress(url, downloadedSize, totalSize, progress, speed);
                    }
                }

                @Override
                public void onSuccess(String url, String filePath) {
                    successList.add(new DownloadInfo(url, filePath));
                    latch.countDown();
                    if (batchListener != null) {
                        batchListener.onSingleSuccess(url, filePath);
                    }
                }

                @Override
                public void onFailure(String url, Exception e) {
                    failList.add(new DownloadFailInfo(url, e));
                    latch.countDown();
                    if (batchListener != null) {
                        batchListener.onSingleFailure(url, e);
                    }
                }

                @Override
                public void onPause(String url, long downloadedSize) {
                    if (batchListener != null) {
                        batchListener.onSinglePause(url, downloadedSize);
                    }
                }

                @Override
                public void onCancel(String url) {
                    if (batchListener != null) {
                        batchListener.onSingleCancel(url);
                    }
                    latch.countDown(); // 取消任务也计数
                }
            });
        }

        // 提交线程池，等待所有任务完成后回调批量结果
        CommThreadPoolUtils.runOnSubThread(() -> {
            try {
                latch.await(); // 阻塞等待所有任务完成
                // 切换到主线程回调批量结果
                CommThreadPoolUtils.runOnMainThread(() -> {
                    if (batchListener != null) {
                        batchListener.onBatchComplete(successList, failList);
                    }
                });
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                if (batchListener != null) {
                    CommThreadPoolUtils.runOnMainThread(() -> batchListener.onBatchFailure(e));
                }
            }
        });
    }

    // -------------------------- 暂停/取消下载 --------------------------

    /**
     * 暂停单个文件下载
     *
     * @param downloadUrl 下载链接
     */
    public void pauseDownload(String downloadUrl) {
        DownloadTask task = mDownloadTaskMap.get(downloadUrl);
        if (task != null && task.isRunning()) {
            task.pause();
        }
    }

    /**
     * 取消单个文件下载（删除已下载文件）
     *
     * @param downloadUrl 下载链接
     */
    public void cancelDownload(String downloadUrl) {
        DownloadTask task = mDownloadTaskMap.get(downloadUrl);
        if (task != null) {
            task.cancel();
            mDownloadTaskMap.remove(downloadUrl);
        }
    }

    /**
     * 取消所有下载任务
     */
    public void cancelAllDownload() {
        for (String url : mDownloadTaskMap.keySet()) {
            cancelDownload(url);
        }
        mDownloadTaskMap.clear();
    }

    // -------------------------- 工具方法 --------------------------

    /**
     * 从 URL 解析文件名
     */
    private String parseFileNameFromUrl(String url) {
        if (url == null) return "unknown_file";
        // 从 URL 末尾截取文件名（处理 ? 后面的参数）
        int lastSlashIndex = url.lastIndexOf("/");
        if (lastSlashIndex != -1) {
            String fileName = url.substring(lastSlashIndex + 1);
            int paramIndex = fileName.indexOf("?");
            if (paramIndex != -1) {
                fileName = fileName.substring(0, paramIndex);
            }
            return fileName.isEmpty() ? "unknown_file" : fileName;
        }
        return "unknown_file";
    }

    /**
     * 获取文件下载路径
     */
    public String getDownloadPath(String saveDir, String fileName) {
        return new File(saveDir, fileName).getAbsolutePath();
    }

    // -------------------------- 下载任务内部类 --------------------------

    /**
     * 单个文件下载任务（实现 Runnable，提交到线程池）
     */
    private class DownloadTask implements Runnable {
        private final String mUrl;
        private final String mSaveDir;
        private final String mFileName;
        private final DownloadListener mListener;
        private volatile boolean isRunning = false; // 是否正在下载
        private volatile boolean isPaused = false;  // 是否暂停
        private volatile boolean isCancelled = false; // 是否取消

        public DownloadTask(String url, String saveDir, String fileName, DownloadListener listener) {
            this.mUrl = url;
            this.mSaveDir = saveDir;
            this.mFileName = fileName;
            this.mListener = listener;
        }

        @Override
        public void run() {
            isRunning = true;
            HttpURLConnection connection = null;
            InputStream is = null;
            RandomAccessFile raf = null;


            String filePath = getDownloadPath(mSaveDir, mFileName);

            try {
                File file = new File(filePath);
                // 检查是否已下载完成（文件存在且大小匹配）
                if (file.exists()) {
                    totalSize = getFileTotalSize(mUrl);
                    if (file.length() == totalSize && totalSize > 0) {
                        if (mListener != null) {
                            CommThreadPoolUtils.runOnMainThread(() -> mListener.onSuccess(mUrl, filePath));
                        }
                        mDownloadTaskMap.remove(mUrl);
                        return;
                    }
                    // 支持断点续传（已下载部分，从断点继续）
                    downloadedSize = file.length();
                }

                // 初始化 HTTP 连接
                connection = (HttpURLConnection) new URL(mUrl).openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(10 * 1000); // 连接超时 10s
                connection.setReadTimeout(30 * 1000);    // 读取超时 30s
                // 断点续传：设置 Range 头（从已下载位置开始）
                if (downloadedSize > 0) {
                    connection.setRequestProperty("Range", "bytes=" + downloadedSize + "-");
                }

                // 响应码校验（200：完整下载，206：断点续传）
                int responseCode = connection.getResponseCode();
                if (responseCode != HttpURLConnection.HTTP_OK && responseCode != HttpURLConnection.HTTP_PARTIAL) {
                    throw new IOException("服务器响应错误：" + responseCode);
                }

                // 获取文件总大小（响应头 Content-Length）
                totalSize = connection.getContentLengthLong();
                if (responseCode == HttpURLConnection.HTTP_PARTIAL) {
                    // 断点续传时，Content-Length 是剩余大小，需加上已下载大小
                    totalSize += downloadedSize;
                }
                if (totalSize <= 0) {
                    throw new IOException("无法获取文件大小");
                }

                // 回调开始下载
                if (mListener != null) {
                    CommThreadPoolUtils.runOnMainThread(() -> mListener.onStart(mUrl, totalSize));
                }

                // 初始化文件写入流（支持断点续传，从文件末尾写入）
                raf = new RandomAccessFile(file, "rw");
                raf.seek(downloadedSize); // 移动到已下载位置

                // 读取数据流并写入文件
                is = connection.getInputStream();
                byte[] buffer = new byte[4096]; // 4KB 缓冲区（平衡性能和内存）
                int len;
                long startTime = System.currentTimeMillis();
                long lastProgressTime = startTime;

                while ((len = is.read(buffer)) != -1) {
                    // 检查是否暂停/取消
                    if (isPaused) {
                        if (mListener != null) {
                            CommThreadPoolUtils.runOnMainThread(() -> mListener.onPause(mUrl, downloadedSize));
                        }
                        return;
                    }
                    if (isCancelled) {
                        // 取消下载，删除已下载文件
                        if (file.exists()) {
                            file.delete();
                        }
                        if (mListener != null) {
                            CommThreadPoolUtils.runOnMainThread(() -> mListener.onCancel(mUrl));
                        }
                        return;
                    }

                    // 写入文件
                    raf.write(buffer, 0, len);
                    downloadedSize += len;

                    // 计算进度和速度（每 500ms 回调一次，避免频繁 UI 刷新）
                    long currentTime = System.currentTimeMillis();
                    if (currentTime - lastProgressTime >= 50) {
                        int progress = (int) ((downloadedSize * 100.0) / totalSize);
                        // 下载速度：KB/s
                        float speed = (downloadedSize - (currentTime - startTime) / 1000f) / 1024f;
                        if (mListener != null) {
                            CommThreadPoolUtils.runOnMainThread(() ->
                                    mListener.onProgress(mUrl, downloadedSize, totalSize, progress, speed)
                            );
                        }
                        lastProgressTime = currentTime;
                    }
                }

                // 下载完成校验（避免未下载完整）
                if (downloadedSize == totalSize) {
                    if (mListener != null) {
                        CommThreadPoolUtils.runOnMainThread(() -> mListener.onSuccess(mUrl, filePath));
                    }
                } else {
                    throw new IOException("下载不完整：已下载 " + downloadedSize + "，总大小 " + totalSize);
                }

            } catch (Exception e) {
                Log.e(TAG, "下载失败：" + mUrl, e);
                if (mListener != null) {
                    CommThreadPoolUtils.runOnMainThread(() -> mListener.onFailure(mUrl, e));
                }
            } finally {
                // 关闭资源
                try {
                    if (is != null) is.close();
                    if (raf != null) raf.close();
                    if (connection != null) connection.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                // 移除任务缓存
                mDownloadTaskMap.remove(mUrl);
                isRunning = false;
            }
        }

        /**
         * 获取文件总大小（单独请求，用于断点续传校验）
         */
        private long getFileTotalSize(String url) throws IOException {
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setRequestMethod("HEAD"); // 仅请求头部信息，不下载文件
            connection.setConnectTimeout(10 * 1000);
            int responseCode = connection.getResponseCode();
            if (responseCode != HttpURLConnection.HTTP_OK) {
                throw new IOException("获取文件大小失败，响应码：" + responseCode);
            }
            long totalSize = connection.getContentLengthLong();
            connection.disconnect();
            return totalSize;
        }

        // 暂停下载
        public void pause() {
            isPaused = true;
            isRunning = false;
        }

        // 取消下载
        public void cancel() {
            isCancelled = true;
            isRunning = false;
        }

        // 是否正在下载
        public boolean isRunning() {
            return isRunning;
        }
    }

    // -------------------------- 监听接口 --------------------------

    /**
     * 单文件下载监听
     */
    public interface DownloadListener {
        /**
         * 下载开始
         *
         * @param url       下载链接
         * @param totalSize 文件总大小（字节）
         */
        void onStart(String url, long totalSize);

        /**
         * 下载进度更新
         *
         * @param url            下载链接
         * @param downloadedSize 已下载大小（字节）
         * @param totalSize      总大小（字节）
         * @param progress       进度百分比（0-100）
         * @param speed          下载速度（KB/s）
         */
        void onProgress(String url, long downloadedSize, long totalSize, int progress, float speed);

        /**
         * 下载成功
         *
         * @param url      下载链接
         * @param filePath 文件保存路径
         */
        void onSuccess(String url, String filePath);

        /**
         * 下载失败
         *
         * @param url 下载链接
         * @param e   异常信息
         */
        void onFailure(String url, Exception e);

        /**
         * 下载暂停
         *
         * @param url            下载链接
         * @param downloadedSize 已下载大小（字节）
         */
        void onPause(String url, long downloadedSize);

        /**
         * 下载取消
         *
         * @param url 下载链接
         */
        void onCancel(String url);
    }

    /**
     * 多文件批量下载监听
     */
    public interface BatchDownloadListener {
        /**
         * 单个文件开始下载
         */
        void onSingleStart(String url, long totalSize);

        /**
         * 单个文件进度更新
         */
        void onSingleProgress(String url, long downloadedSize, long totalSize, int progress, float speed);

        /**
         * 单个文件下载成功
         */
        void onSingleSuccess(String url, String filePath);

        /**
         * 单个文件下载失败
         */
        void onSingleFailure(String url, Exception e);

        /**
         * 单个文件暂停
         */
        void onSinglePause(String url, long downloadedSize);

        /**
         * 单个文件取消
         */
        void onSingleCancel(String url);

        /**
         * 所有文件下载完成（成功+失败）
         *
         * @param successList 成功下载的文件信息
         * @param failList    下载失败的文件信息
         */
        void onBatchComplete(List<DownloadInfo> successList, List<DownloadFailInfo> failList);

        /**
         * 批量下载异常（如计数锁中断）
         */
        void onBatchFailure(Exception e);
    }

    // -------------------------- 数据模型类 --------------------------

    /**
     * 下载成功的文件信息
     */
    public static class DownloadInfo {
        private final String url;
        private final String filePath;

        public DownloadInfo(String url, String filePath) {
            this.url = url;
            this.filePath = filePath;
        }

        public String getUrl() {
            return url;
        }

        public String getFilePath() {
            return filePath;
        }
    }

    /**
     * 下载失败的文件信息
     */
    public static class DownloadFailInfo {
        private final String url;
        private final Exception exception;

        public DownloadFailInfo(String url, Exception exception) {
            this.url = url;
            this.exception = exception;
        }

        public String getUrl() {
            return url;
        }

        public Exception getException() {
            return exception;
        }
    }

    // -------------------------- 静态辅助类（获取 App 上下文） --------------------------

    /**
     * 全局上下文工具类（需在 Application 中初始化）
     */
    public static class AppUtils {
        private static volatile android.content.Context sAppContext;

        /**
         * 在 Application 中初始化
         */
        public static void init(android.content.Context appContext) {
            if (appContext != null) {
                sAppContext = appContext.getApplicationContext();
            }
        }

        /**
         * 获取全局上下文
         */
        public static android.content.Context getAppContext() {
            if (sAppContext == null) {
                throw new IllegalStateException("AppUtils 未初始化，请在 Application 中调用 AppUtils.init(this)");
            }
            return sAppContext;
        }
    }
}